﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using GeoFramework;
using GeoFramework.Gps;
using GeoFramework.Gps.IO;
using LetsDoIt.BO;
using LetsDoIt.Interfaces;
using LetsDoIt.Localization;
using LetsDoIt.Common;

namespace LetsDoIt.Forms
{
	public partial class IntroForm : UserControl, INavigationForm
	{
        delegate void UpdateUI();

        List<Device> listDevices = new List<Device>();
        private Position currentPosition = Position.Empty;
        private DilutionOfPrecision currentPrecision;

	    public string CurrentDevice = string.Empty;
	    private bool isInDetection;

	    #region Implementation of INavigationForm

		public MainForm HostForm { get; set; }
		public string Identity { get; set; }
        public bool IsActive { get; set; }

		public void NavigationEnter(object sender)
		{
			//
            bool hasCases = WastesLocalFactory.HasCases();
		    btnViewCases.Enabled = hasCases;
		    HostForm.mnuViewCases.Enabled = hasCases;
		    btnPostCases.Enabled = hasCases;
            //
            nmeaInterpreter1.PositionChanged += new EventHandler<PositionEventArgs>(nmeaInterpreter1_PositionChanged);
            nmeaInterpreter1.HorizontalDilutionOfPrecisionChanged += new EventHandler<DilutionOfPrecisionEventArgs>(nmeaInterpreter1_HorizontalDilutionOfPrecisionChanged);
            //
            UpdateGPSdevice();
		    UpdateCoordinates();
		}
		public void NavigationLeave()
		{
			//nothing
            nmeaInterpreter1.PositionChanged -= new EventHandler<PositionEventArgs>(nmeaInterpreter1_PositionChanged);
            nmeaInterpreter1.HorizontalDilutionOfPrecisionChanged -= new EventHandler<DilutionOfPrecisionEventArgs>(nmeaInterpreter1_HorizontalDilutionOfPrecisionChanged);
		}

		#endregion


		#region ctor

		public IntroForm(MainForm hostForm, string identity)
		{
			HostForm = hostForm;
			Identity = identity;
			InitializeComponent();
			
			//
			this.picLogo.Image = Properties.Resources.ldir_logo_90;
			this.picDeviceState.Image = Properties.Resources.gps_on_gray;
			//

			InitGpsDetection();
			//TryGpsConnect();
			SetVisibleControlsByGpsDevice();
		}

		#endregion ctor


		#region methods

		private void SetVisibleControlsByGpsDevice()
		{
			bool isGpsDeviceSet = nmeaInterpreter1.Device != null && nmeaInterpreter1.Device.IsOpen;
			btnSelectStartGps.Visible = !isGpsDeviceSet;
			lblDevice.Visible = isGpsDeviceSet;
			lblLat.Visible = isGpsDeviceSet;
			lblLng.Visible = isGpsDeviceSet;
			lblPrecision.Visible = isGpsDeviceSet;
		}

		public void InitGpsDetection()
		{
            if (!isInDetection)
            {
                isInDetection = true;
                Devices.DeviceDetectionStarted += new EventHandler(Devices_DeviceDetectionStarted);
                Devices.DeviceDetectionCompleted += new EventHandler(Devices_DeviceDetectionCompleted);
                Devices.DeviceDetected += new EventHandler<DeviceEventArgs>(Devices_DeviceDetected);
                Devices.DeviceDetectionAttempted += new EventHandler<DeviceEventArgs>(Devices_DeviceDetectionAttempted);
                Devices.DeviceDetectionAttemptFailed += new EventHandler<DeviceDetectionExceptionEventArgs>(Devices_DeviceDetectionAttemptFailed);

                Devices.BeginDetection();
            }
		}

		private void CloseGpsDetection()
		{
			Devices.DeviceDetectionStarted -= new EventHandler(Devices_DeviceDetectionStarted);
			Devices.DeviceDetectionCompleted -= new EventHandler(Devices_DeviceDetectionCompleted);
			Devices.DeviceDetected -= new EventHandler<DeviceEventArgs>(Devices_DeviceDetected);
			Devices.DeviceDetectionAttempted -= new EventHandler<DeviceEventArgs>(Devices_DeviceDetectionAttempted);
			Devices.DeviceDetectionAttemptFailed -= new EventHandler<DeviceDetectionExceptionEventArgs>(Devices_DeviceDetectionAttemptFailed);
		}


		private void Log(string message)
		{
			txtLog.Text += message + "\r\n";
		}

		#endregion methods


		#region events

		void Devices_DeviceDetectionAttemptFailed(object sender, DeviceDetectionExceptionEventArgs e)
		{
            this.Invoke((ThreadStart)delegate()
            {
				// Update the log with the message
				Log("Err: " + e.Device.Name + ": " + e.Exception.Message);
			});
		}

		void Devices_DeviceDetectionAttempted(object sender, DeviceEventArgs e)
		{
            this.Invoke((ThreadStart)delegate()
            {
				// Update the log
				Log("Testing " + e.Device.Name + "...");
			});
		}

		void Devices_DeviceDetectionCompleted(object sender, EventArgs e)
		{
            this.Invoke((ThreadStart)delegate()
            {
		        this.Invoke(new UpdateUI(Devices_DeviceDetectionCompleted_UI));
                //// Change the cursor back to normal
                //Cursor.Current = Cursors.Default;

                //// Update the log to show that the search has completed
                //Log("Device detection has completed.");

                //CloseGpsDetection();
                //isInDetection = false;
                //if(HostForm.Settings.UseGps)
                //    TryGpsConnect();
			});
		}

        public void Devices_DeviceDetectionCompleted_UI()
        {
            // Change the cursor back to normal
            Cursor.Current = Cursors.Default;

            // Update the log to show that the search has completed
            Log("Device detection has completed.");

            CloseGpsDetection();
            isInDetection = false;
            if (HostForm.Settings.UseGps)
                TryGpsConnect();
        }

	    public void TryGpsConnect()
		{
            if (!isInDetection)
            {
                picDeviceState.Image = Properties.Resources.gps_on_red;
                CurrentDevice = string.Empty;
                if (HostForm.Settings != null && !string.IsNullOrEmpty(HostForm.Settings.GpsDeviceName))
                {
                    //try to connect to the gps from settings
                    foreach (Device device in Devices.GpsDevices)
                    {
                        if (device.Name == HostForm.Settings.GpsDeviceName)
                        {
                            //take first gps 
                            CurrentDevice = device.Name;
                            device.Connected += new EventHandler(dvs_Connected);
                            nmeaInterpreter1.Start(device);
                        }
                    }
                }
                else
                {
                    if (listDevices.Count > 0)
                    {
                        //take first gps 
                        Device dvs = listDevices[0];
                        CurrentDevice = dvs.Name;
                        //
                        dvs.Connected += new EventHandler(dvs_Connected);
                        nmeaInterpreter1.Start(dvs);
                    }
                }
                //
                UpdateGPSdevice();
            }
		}

	    private void UpdateGPSdevice()
	    {
	        lblDevice.Text = string.Format(
	            ResourceManager.Instance.GetString(@"MainForm_lblDevice"),
	            CurrentDevice);
	    }

	    void Devices_DeviceDetectionStarted(object sender, EventArgs e)
		{
			this.Invoke((ThreadStart)delegate
			{
				// Show that detection has been started
				Log("Device detection has started.");
			});
		}

		void Devices_DeviceDetected(object sender, DeviceEventArgs e)
		{
            this.Invoke((ThreadStart)delegate()
            {
				// Update the log to show the success
				Log(e.Device.Name + " is a GPS device.");
				lstDevices.Items.Add(e.Device.Name);
				listDevices.Add(e.Device);
			});
		}

		private void nmeaInterpreter1_PositionChanged(object sender, PositionEventArgs e)
        {
		    currentPosition = e.Position;
            if (IsActive)
            {
                this.Invoke(new UpdateUI(nmeaInterpreter1_PositionChanged_UI));
            }
        }
        
        public void nmeaInterpreter1_PositionChanged_UI()
        {
            // Update the latitude and longitude
            UpdateCoordinates();

            timerResetCreateButton.Enabled = false;
            timerResetCreateButton.Enabled = true;

            if (currentPrecision.EstimatedPrecision.ToMeters().Value < Limits.MAX_PRECISION_LIMIT)
            {
                btnCreateCase.Enabled = true;
                picDeviceState.Image = Properties.Resources.gps_on_green;
            }
            else
            {
                btnCreateCase.Enabled = false;
                picDeviceState.Image = Properties.Resources.gps_on_orange;
            }
        }

	    private void UpdateCoordinates()
	    {
	        lblLat.Text = string.Format(
	            ResourceManager.Instance.GetString(@"MainForm_lblLat"),
                currentPosition.Latitude);
	        lblLng.Text = string.Format(
	            ResourceManager.Instance.GetString(@"MainForm_lblLng"),
                currentPosition.Longitude);
	        lblPrecision.Text = string.Format(
	            ResourceManager.Instance.GetString(@"MainForm_lblPrecision"),
	            currentPrecision.EstimatedPrecision.ToMeters());
            Application.DoEvents();
	    }

	    private void nmeaInterpreter1_HorizontalDilutionOfPrecisionChanged(object sender, DilutionOfPrecisionEventArgs e)
        {
	        currentPrecision = e.DilutionOfPrecision;
            if (IsActive)
            {
                this.Invoke(new UpdateUI(nmeaInterpreter1_HorizontalDilutionOfPrecisionChanged_UI));
            }
        }

        public void nmeaInterpreter1_HorizontalDilutionOfPrecisionChanged_UI()
        {
            UpdateCoordinates();
        }


	    private void btnStart_Click(object sender, EventArgs e)
		{
			try
			{
				if (listDevices.Count > 0 && lstDevices.SelectedIndex >= 0)
				{
					Device dvs = listDevices[lstDevices.SelectedIndex];
					dvs.Connected += new EventHandler(dvs_Connected);
					if (dvs is BluetoothDevice)
					{
						lblDevice.Text = string.Format("Device: {0}", (dvs as BluetoothDevice).Name);
					}
					else
					{
						lblDevice.Text = string.Format("Device: {0}", dvs.Name);
					}
					Application.DoEvents();

					nmeaInterpreter1.Start(dvs);
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.ToString(), "Unable to Connect", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
			}
		}

		void dvs_Connected(object sender, EventArgs e)
		{
			Device dvs = (sender as Device);
			if (dvs != null) 
				HostForm.Settings.GpsDeviceName = dvs.Name;
			SettingsFactory.SaveSettings(HostForm.Settings);

			if (dvs != null) 
				dvs.Connected -= new EventHandler(dvs_Connected);
		}

		private void btnCreateCase_Click(object sender, EventArgs e)
		{
			HostForm.CurrentPosition = currentPosition;
			HostForm.CurrentPrecision = currentPrecision;
			CaseForm frmCase = (HostForm.GetFormByIdentity(NavigationForms.FORM_CASE) as CaseForm);
			if (frmCase != null)
			{
				frmCase.Mode = WorkMode.New;

				CaseInfo newCaseInfo = new CaseInfo();
				newCaseInfo.ID = WastesLocalFactory.GetNewCaseID();
				newCaseInfo.CaseDateTime = DateTime.Now.ToUniversalTime();
				newCaseInfo.Latitude = currentPosition.Latitude.DecimalDegrees;
				newCaseInfo.Longitude = currentPosition.Longitude.DecimalDegrees;
				newCaseInfo.Precision = (int) currentPrecision.EstimatedPrecision.ToMeters().Value;
                //init with default values
			    newCaseInfo.Diameter = 1;
                newCaseInfo.Heigth = 0;
			    newCaseInfo.Length = 1;
			    newCaseInfo.Width = 1;
			    newCaseInfo.BagEq = 1;
			    newCaseInfo.IsDispersed = false;
			    newCaseInfo.NotRecyclableContent = 100;
                newCaseInfo.PaperContent = 0;
                newCaseInfo.RubberContent = 0;
                newCaseInfo.GlassContent = 0;
                newCaseInfo.PlasticContent = 0;
                newCaseInfo.MetalContent = 0;
                newCaseInfo.MatterialsContent = 0;

				frmCase.Case = newCaseInfo; 
				//
				frmCase.ResetCase();
			}
			//clear photos
			PhotosForm frmPhotos = HostForm.GetFormByIdentity(NavigationForms.FORM_PHOTOS) as PhotosForm;
			if (frmPhotos!=null)
				frmPhotos.ResetPhotos();

			HostForm.NavigateTo(this, NavigationForms.FORM_CASE);
		}


		private void nmeaInterpreter1_Started(object sender, EventArgs e)
		{
            this.Invoke(new UpdateUI(nmeaInterpreter1_Started_UI));
		}

        public void nmeaInterpreter1_Started_UI()
        {
            picDeviceState.Image = Properties.Resources.gps_on_orange;
            SetVisibleControlsByGpsDevice();
        }

	    private void nmeaInterpreter1_ConnectionLost(object sender, ExceptionEventArgs e)
		{
            this.Invoke(new UpdateUI(nmeaInterpreter1_ConnectionLost_UI));
		}

        public void nmeaInterpreter1_ConnectionLost_UI()
        {
            picDeviceState.Image = Properties.Resources.gps_on_red;
            SetVisibleControlsByGpsDevice();
        }

	    private void btnSelectGps_Click(object sender, EventArgs e)
		{
			HostForm.NavigateTo(this, NavigationForms.FORM_GPS_SELECT);
		}

		private void btnViewCases_Click(object sender, EventArgs e)
		{
			HostForm.NavigateTo(this, NavigationForms.FORM_VIEW_CASES);
		}

        private void btnPostCases_Click(object sender, EventArgs e)
        {
            //
            HostForm.NavigateTo(this, NavigationForms.FORM_UPLOAD_CASES);
        }

		#endregion events

        private void timerResetCreateButton_Tick(object sender, EventArgs e)
        {
            ResetGeoData();
        }

	    public void CloseGpsConnection()
	    {
            if (nmeaInterpreter1.Device!=null)
                nmeaInterpreter1.Stop();
            picDeviceState.Image = Properties.Resources.gps_on_gray;
            ResetGeoData();
	    }

	    private void ResetGeoData()
	    {
	        btnCreateCase.Enabled = false;
	        currentPosition = Position.Empty;
	        currentPrecision = DilutionOfPrecision.Invalid;
	        UpdateCoordinates();
	    }
	}
}
